package com.untour.im.client.handler;

import com.untour.im.client.TcpClient;
import com.untour.im.client.handler.policy.RetryPolicy;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Slf4j
@ChannelHandler.Sharable
public class ReconnectHandler extends ChannelInboundHandlerAdapter {
 
    private int retries = 0;

    private RetryPolicy retryPolicy;
 
    private TcpClient tcpClient;
 
    public ReconnectHandler(TcpClient tcpClient) {
        this.tcpClient = tcpClient;
    }
 
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("Successfully established a connection to the server.");
        retries = 0;
        ctx.fireChannelActive();
    }
 
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (retries == 0 ) {
            log.info("Lost the TCP connection with the server.");
            ctx.close();
        }
 
        boolean allowRetry = getRetryPolicy().allowRetry(retries);
        if (allowRetry) {
 
            long sleepTimeMs = getRetryPolicy().getSleepTimeMs(retries);
            retries++;
            log.info(String.format("Try to reconnect to the server after %dms. Retry count: %d.", sleepTimeMs,retries ));
 
            final EventLoop eventLoop = ctx.channel().eventLoop();
            eventLoop.schedule(() -> {
                log.info("Reconnecting ...");
                tcpClient.connect();
            }, sleepTimeMs, TimeUnit.MILLISECONDS);
        }
        ctx.fireChannelInactive();
    }
 
 
    private RetryPolicy getRetryPolicy() {
        if (this.retryPolicy == null) {
            this.retryPolicy = tcpClient.getRetryPolicy();
        }
        return this.retryPolicy;
    }
}